#ifndef BLOQUEBSHARP_H_
#define BLOQUEBSHARP_H_

#include "Bloque.h"

namespace Toolkit
{

class BloqueBSharp: public Bloque
{
public:
    BloqueBSharp(const unsigned long int &tamanoBloque, const TipoSerializacion&);
    virtual ~BloqueBSharp();

    virtual void agregar(Componente*, const Clave&);
    virtual Componente* buscar(const Clave&);

    unsigned long getNivelNodo() const;
    void setNivelNodo(const unsigned long &);

    unsigned long int getDireccion() const;
    void setDireccion(const unsigned long int &direccion);

    bool estaUnderflow() const;
    bool estaOverflow() const;
    bool estaOverflowRaiz() const;
    bool esHoja () const;

    /**
     * Devuelve el sucesor derecho al primer serparador menor a la clave pasada del bloque.
     * Si la clave esta presente en este nodo como separador,
     * devuelve el sucesor izquierdo.
     */
    unsigned long int nodoSiguiente(const Clave &clave) const;

    /**
     * Suponiendo que la clave sea la maxima de un hijo de este nodo, devuelve
     * la direccion de su sibling derecho. Si es el hijo más derecho, devuelve -1.
     */
    long int siblingDerecho(const Clave &clave) const;

    /**
     * Suponiendo que la clave sea la maxima de un hijo de este nodo, devuelve
     * la direccion de su sibling izquierdo. Si es el hijo más izquierdo, devuelve -1.
     */
    long int siblingIzquierdo(const Clave &clave) const;

	/**
	 * Verifica si se puede solucionar un underflow u overflow (o ambos),
	 * entre este nodo y su adyacente derecho, mediante la redistribución de
	 * claves.
	 * */
    bool sePuedeBalancearEnDos(const BloqueBSharp &siblingDerecho) const;

    /**
     * Devuelve false si el balanceo entre tres produce UF en el sibling derecho.
     */
    bool sePuedeBalancearEnTres(const BloqueBSharp &nuevoNodo, const BloqueBSharp &siblingDerecho) const;


	/* Redistribuye las claves entre este nodo y su adyacente derecho, tratando de dejar
	 * un promedio de uso del espacio disponible, y si no puede al menos dejandolos en estado consistente.
	 * Se supone que se llamará solo si  sePuedeBalancearEnDos da positivo. Si se llega a un estado
	 * inconsistente se arroja una excepcion.
	 * */
    void balancearEnDos(BloqueBSharp &siblingDerecho);

    /* Redistribuye las claves de este nodo y el derecho, para llenar un nuevo nodo entre esoso dos.
     * Se prioriza dejar llenos el izquierdo y el central, de manera que es posible que el derecho
     * quede en underflow.
     * */
    void balancearEnTres(BloqueBSharp &nuevoNodo, BloqueBSharp &siblingDerecho);

    bool sePuedeUnirTresEnDos(const BloqueBSharp &nodoCentral, const BloqueBSharp &siblingDerecho) const;

    void unirTresEnDos(BloqueBSharp &nodoAVaciar, BloqueBSharp &siblingDerecho);

    virtual Clave* claveMaxima() const;

    virtual Clave* claveMinima() const;

    BloqueBSharp* partirRaiz();

    bool sePuedeUnirRaiz(const BloqueBSharp &bloqueBSharp) const;

    void unirRaiz(BloqueBSharp &bloqueBSharp);

    bool getClaveSiguiente(const Clave &clave, Clave*& claveSiguiente);

    list<unsigned long int> imprimirYPoisciones() const;

    virtual Componente *clonar() const;

protected:
    virtual string especializarSerializacion() const;
    virtual void especializarHidratacion(stringstream&);

private:
    unsigned long nivelNodo;

    /**
     * Esta direccion va a ser el sucesor izquierdo para nodos,
     * y la direccion de la hoja siguiente, si es una hoja.
     */
    unsigned long int direccion;
};

}

#endif /* BLOQUEBSHARP_H_ */
